const getContentWidth = (list, blockWidth, blockXSpacing) => {
  let max = list.reduce(function (res, cur) {
    if (list.findIndex(e => e.pid === cur['id']) === -1) {
      res++
    }
    return res
  }, 0)
  return max * blockWidth + (max - 1) * blockXSpacing + blockWidth / 2
}

const getContentHeight = (list, blockHeight) => {
  let max = list.reduce(function (res, cur) {
    res.push(cur['level'])
    return res
  }, [])
  return (Math.max(...max) + 1) * blockHeight * 3
}

let countNumber = 0
const initBlock = (list, blockWidth, blockXSpacing, blockYSpacing) => {
  countNumber = 0
  if (Array.isArray(list) && list.length > 0) {
    list = sortList(list, 'level')
    for (let i = 0; i < list.length; i++) {
      list[i]['x'] = getBlockX(list, list[i], blockWidth, blockXSpacing)
      list[i]['y'] = getBlockY(list, i, blockXSpacing, blockYSpacing)
    }
    stackArithmeticX(list, blockWidth, blockXSpacing)
    moveLeft(list, blockWidth)
  }
}

const moveLeft = (list, blockWidth) => {
  list = sortList(list, 'x')
  let moveNumber = list[0].x - blockWidth / 2 > 0 ? list[0].x - blockWidth / 2 : 0
  for (let i = 0; i < list.length; i++) {
    list[i].x -= moveNumber
  }
}

const getBlockX = (list, item, blockWidth, blockXSpacing) => {
  if (list.findIndex(e => e.id === item.pid) > -1) {
    let pItem = list.find(e => e.id === item.pid)
    let pidIsSameBlockList = sortList(list.filter(e => e.pid === pItem.id), 'id')
    if (pidIsSameBlockList.length > 1) {
      let samePidBlockAllWidth = 0
      samePidBlockAllWidth = pidIsSameBlockList.length * blockWidth + (pidIsSameBlockList.length - 1) * blockXSpacing
      let index = pidIsSameBlockList.findIndex(e => e.id === item.id)
      return pItem.x + blockWidth / 2 - samePidBlockAllWidth / 2 + (index > -1 ? index * 500 : 0) + index * blockXSpacing
    } else {
      return pItem.x
    }
  } else {
    return getContentWidth(list, blockWidth, blockXSpacing) / 2 - blockWidth / 2
  }
}
const getBlockY = (list, i, blockXSpacing, blockYSpacing) => {
  return list[i].level * blockYSpacing + blockXSpacing * 5
}

const sortList = (list, attr) => {
  if (!Array.isArray(list)) {
    return []
  }
  let tempList = list.sort(compare(attr))
  function compare (prop) {
    return function (a, b) {
      return a[prop] - b[prop]
    }
  }
  return tempList
}

const stackArithmeticX = (list, blockWidth, blockXSpacing) => {
  let levelList = []
  for (let i = 0; i < list.length; i++) {
    if (!levelList.includes(list[i].level)) {
      levelList.push(list[i].level)
    }
  }
  let newData = new Map()
  for (let i = 0; i < levelList.length; i++) {
    if (!newData.get(levelList[i])) {
      newData.set(levelList[i], list.filter(e => e.level === levelList[i]))
    }
  }

  for (const [level, sameLevelList] of newData) {
    let stackPidList = getStackPidList(sameLevelList, blockWidth, blockXSpacing)
    if (level > 0 && stackPidList.length > 1) {
      let stackPitemList = list.filter(e => stackPidList.includes(e.id))
      for (let i = 0; i < stackPitemList.length; i++) {
        if (i < stackPitemList.length - 1) {
          let before = getSnodeWidth(list, stackPitemList[i].id, blockWidth, blockXSpacing)
          let after = getSnodeWidth(list, stackPitemList[i + 1].id, blockWidth, blockXSpacing)
          // if (stackPitemList[i].x < stackPitemList[i + 1].x && (stackPitemList[i].x + blockWidth / 2 + before / 2) + (stackPitemList[i + 1].x + blockWidth / 2 + after / 2)) {
          // if (stackPitemList[i].x < stackPitemList[i + 1].x && stackPitemList[i + 1].x - stackPitemList[i].x < before / 2 + after / 2) {
          let sItemList = getAllSidList(list, stackPitemList[i + 1].id)
          if (sItemList.length === 1) {
            list[list.findIndex(e => e.id === stackPitemList[i + 1].id)].x = stackPitemList[i].x + before / 2 + after / 2 + blockXSpacing
            let sItemIndex = list.findIndex(e => e.id === sItemList[0])
            list[sItemIndex].x = list[list.findIndex(e => e.id === stackPitemList[i + 1].id)].x
          } else {
            for (let j = 0; j < sItemList.length; j++) {
              let sItemIndex = list.findIndex(e => e.id === sItemList[j])
              sItemIndex > -1 && (list[sItemIndex].x += (stackPitemList[i].x + before / 2 + after / 2 + blockXSpacing) - list[list.findIndex(e => e.id === stackPitemList[i + 1].id)].x)
            }
            list[list.findIndex(e => e.id === stackPitemList[i + 1].id)].x = stackPitemList[i].x + before / 2 + after / 2 + blockXSpacing
          }
          // }
        }
      }
    } else if (stackPidList.length === 1) {
      let stackItemList = list.filter(e => stackPidList.includes(e.pid))
      let tempSortList = sortList(stackItemList, 'x')
      let offsetBlockIndex = () => {
        let temp = -2
        for (let i = 0; i < tempSortList.length; i++) {
          if (i < tempSortList.length - 1 && tempSortList[i + 1].x < tempSortList[i].x + blockWidth + blockXSpacing) {
            temp = i + 1
            break
          }
        }
        return temp
      }
      if (offsetBlockIndex() > -1) {
        let offsetItemIndex = list.findIndex(e => e.id === tempSortList[offsetBlockIndex()].id)
        list[offsetItemIndex].x += blockWidth + blockXSpacing
      }
    } else {
    }
  }
  let hasStack = checkHasStackX(list, blockWidth, blockXSpacing)
  if (hasStack) {
    countNumber++
    let maxXindex = list.findIndex(e => e.x > blockWidth * 100)
    countNumber < 100 && maxXindex === -1 && stackArithmeticX(list, blockWidth, blockXSpacing)
  }
}

const checkHasStackX = (list, blockWidth, blockXSpacing) => {
  let hasStack = false
  let levelList = []
  for (let i = 0; i < list.length; i++) {
    if (!levelList.includes(list[i].level)) {
      levelList.push(list[i].level)
    }
  }
  let newData = new Map()
  for (let i = 0; i < levelList.length; i++) {
    if (!newData.get(levelList[i])) {
      newData.set(levelList[i], list.filter(e => e.level === levelList[i]))
    }
  }
  for (const [level, sameLevelList] of newData) {
    let stackPidList = getStackPidList(sameLevelList, blockWidth, blockXSpacing)
    if (level > 0 && stackPidList.length > 0) {
      hasStack = true
    }
  }
  return hasStack
}

const getStackPidList = (sameLevelList, blockWidth, blockXSpacing) => {
  let stackPidList = []
  let tempList = sortList(sameLevelList, 'x')
  for (let i = 0; i < tempList.length; i++) {
    if (i < tempList.length - 1 && tempList[i].x + blockWidth + blockXSpacing > tempList[i + 1].x) {
      stackPidList.push(tempList[i].pid)
      stackPidList.push(tempList[i + 1].pid)
    }
  }
  stackPidList = Array.from(new Set(stackPidList))
  return stackPidList
}

const getSnodeWidth = (list, id, blockWidth, blockXSpacing) => {
  let sNodeWidth = 0
  let sNodeList = list.filter(e => e.pid === id)
  if (sNodeList.length > 0) {
    sNodeWidth = sNodeList.length * blockWidth + (sNodeList.length - 1) * blockXSpacing
  }
  return sNodeWidth
}

const getAllSidList = (list, id) => {
  let sIdList = []
  let temp = list.filter(e => e.pid === id)
  for (let i = 0; i < temp.length; i++) {
    sIdList = [...sIdList, temp[i].id, ...getAllSidList(list, temp[i].id)]
  }
  return sIdList
}

const resetDataLists = (flowSetting, botId) => {
  let oldList = flowSetting.blocks
  let tempList = []
  for (let i = 0; i < oldList.length; i++) {
    let parentNodeIndex = oldList.findIndex(e => e.id === oldList[i].parent)
    tempList.push({
      ...JSON.parse(oldList[i].attr[2].blockinfo),
      blockId: JSON.parse(oldList[i].attr[2].blockinfo).id,
      id: oldList[i].id,
      pid: oldList[i].parent,
      level: 0,
      selfTrackId: oldList[i].attr[6].trackid,
      selfTriggerId: parentNodeIndex > -1 ? oldList[parentNodeIndex].attr[6].trackid : botId
    })
  }
  tempList = sortList(tempList, 'id')
  const setLevel = (pid, id) => {
    let pIndex = tempList.findIndex(e => e.id === pid)
    let index = tempList.findIndex(e => e.id === id)
    if (pIndex > -1) {
      tempList[index].level = tempList.find(e => e.id === pid).level + 1
    }
  }
  const resetList = () => {
    for (let i = 0; i < tempList.length; i++) {
      setLevel(tempList[i].pid, tempList[i].id)
    }
    if (tempList.filter(e => e.level === 0).length > 1) {
      resetList()
    }
  }
  resetList()
  return tempList
}
const resetDataListsName = (dataSource, sysBotScriptList) => {
  dataSource.forEach(v => {
    v.name = sysBotScriptList.find(vi => vi.trackId === v.selfTrackId).name
  })
  return [...dataSource]
}

const deleteBlocks = (list, deleteId) => {
  let data = list.map(e => e)
  let deleteIdList = [deleteId]
  let nowIndex = data.findIndex(e => e.id === deleteId)
  nowIndex > -1 && data.splice(nowIndex, 1)
  const clearItem = (data) => {
    for (let i = 0; i < data.length; i++) {
      if (deleteIdList.includes(data[i].pid)) {
        deleteIdList.push(data[i].id)
        data.splice(i, 1)
      }
    }
    if (data.findIndex(e => deleteIdList.includes(e.pid)) > -1) {
      clearItem(data)
    }
  }
  clearItem(data)
  return data
}

export {
  getContentWidth,
  getContentHeight,
  initBlock,
  resetDataLists,
  resetDataListsName,
  deleteBlocks
}
